//
// MRectangleSelector.java
//
package com.photoexpert;

import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;

class MRectangleSelector implements MouseListener, MouseMotionListener {

    static MRectangleSelector Instance() {
        if(_instance == null) {
            _instance = new MRectangleSelector();
            Presentor.Instance().addMouseListener(_instance);
            Presentor.Instance().addMouseMotionListener(_instance);
        }
        return _instance;
    }

    void reset() {
        _mouseDown = false;
        _cursor = Cursor.DEFAULT_CURSOR;
        if(_selection != null) {
            _selection.destroy();
            _selection = null;
        }
        _presentor.setCursor(Cursors._defaultCursor);
    }

    void selectAll() {
        _selection = new RectSelection();
        _selection.setPoint(0, 0);
        Dimension max = _presentor.getPreferredSize();
        _selection.setDimension(max.width - 1, max.height - 1);
        _selection.startDrawBorder();
    }

    RectSelection getSelection() { return _selection; }

    void zoomRateChanged() {
        if(_selection != null)
            _selection.zoomRateChanged();
    }

    @Override
    public void mouseClicked(MouseEvent e) {
        if(_presentor.getMouseMode() != Presentor.MOUSE_MODES.SELECTING_RECT)
            return;
        reset();
    }

    @Override
    public void mousePressed(MouseEvent e) {
        if(_presentor.getMouseMode() != Presentor.MOUSE_MODES.SELECTING_RECT)
            return;
        _mouseDown = true;
        if(_cursor == Cursor.DEFAULT_CURSOR) {
            if(_selection != null) {
                _selection.destroy();
                _selection = null;
            }
            _selection = new RectSelection();
            _selection.setPoint(e.getX(), e.getY());
            _cursor = Cursor.SE_RESIZE_CURSOR;
        }
    }

    @Override
    public void mouseReleased(MouseEvent e) {
        if(_presentor.getMouseMode() != Presentor.MOUSE_MODES.SELECTING_RECT)
            return;
        _mouseDown = false;
    }

    @Override
    public void mouseEntered(MouseEvent e) { }

    @Override
    public void mouseExited(MouseEvent e) { }

    @Override
    public void mouseDragged(MouseEvent e) {
        if(_presentor.getMouseMode() != Presentor.MOUSE_MODES.SELECTING_RECT)
            return;
        if(!_mouseDown)
            return;
        Dimension max = _presentor.getPreferredSize();
        RectSelection.Area area = _selection.getScreenArea();
        int x = area._x;
        int y = area._y;
        int width = area._width;
        int height = area._height;
        int cursorX = e.getX();
        int cursorY = e.getY();
        if(cursorX < 0) cursorX = 0;
        if(cursorX > max.width - 1) cursorX = max.width - 1;
        if(cursorY < 0) cursorY = 0;
        if(cursorY > max.height - 1) cursorY = max.height - 1;
        if(_cursor == Cursor.SE_RESIZE_CURSOR) {
            area._width = cursorX - x;
            area._height = cursorY - y;
        } else if(_cursor == Cursor.NW_RESIZE_CURSOR) {
            area._x = cursorX;
            area._y = cursorY;
            area._width = x + area._width - area._x;
            area._height = y + area._height - area._y;
        }
        else if(_cursor == Cursor.NE_RESIZE_CURSOR) {
            area._y = cursorY;
            area._width = cursorX - x;
            area._height = y + area._height - area._y;
        }
        else if(_cursor == Cursor.SW_RESIZE_CURSOR) {
            area._x = cursorX;
            area._width = x + area._width - area._x;
            area._height = cursorY - y;
        }
        else if(_cursor == Cursor.N_RESIZE_CURSOR) {
            area._y = cursorY;
            area._height = y + area._height - area._y;
        }
        else if(_cursor == Cursor.W_RESIZE_CURSOR) {
            area._x = cursorX;
            area._width = x + area._width - area._x;
        }
        else if(_cursor == Cursor.E_RESIZE_CURSOR)
            area._width = cursorX - x;
        else if(_cursor == Cursor.S_RESIZE_CURSOR)
            area._height = cursorY - y;
        if(x > area._x)
            x = area._x;
        if(y > area._y)
            y = area._y;
        if(width < area._width)
            width = area._width;
        if(height < area._height)
            height = area._height;
        _presentor.repaint(0, x, y, width + 1, height + 1);
        _selection.startDrawBorder();
        App.Instance().selectionBecomeValid(true);
    }

    @Override
    public void mouseMoved(MouseEvent e) {
        if(_presentor.getMouseMode() != Presentor.MOUSE_MODES.SELECTING_RECT)
            return;
        if(_mouseDown || _selection == null)
            return;
        int x = e.getX();
        int y = e.getY();
        RectSelection.Area area = _selection.getScreenArea();
        int x2 = area._x + area._width;
        int y2 = area._y + area._height;
        _cursor = Cursor.DEFAULT_CURSOR;
        Cursor cursor = Cursors._defaultCursor;
        if(Math.abs(x - area._x) < 5)
            if(Math.abs(y - area._y) < 5) {
                _cursor = Cursor.NW_RESIZE_CURSOR;
                cursor = Cursors._nwCursor;
            } else if(Math.abs(y - y2) < 5) {
                _cursor = Cursor.SW_RESIZE_CURSOR;
                cursor = Cursors._swCursor;
            } else {
                _cursor = Cursor.W_RESIZE_CURSOR;
                cursor = Cursors._wCursor;
            }
        else if(Math.abs(x - x2) < 5)
            if(Math.abs(y - area._y) < 5) {
                _cursor = Cursor.NE_RESIZE_CURSOR;
                cursor = Cursors._neCursor;
            } else if(Math.abs(y - y2) < 5) {
                _cursor = Cursor.SE_RESIZE_CURSOR;
                cursor = Cursors._seCursor;
            } else {
                _cursor = Cursor.E_RESIZE_CURSOR;
                cursor = Cursors._eCursor;
            }
        else if(Math.abs(y - area._y) < 5) {
            _cursor = Cursor.N_RESIZE_CURSOR;
            cursor = Cursors._nCursor;
        } else if(Math.abs(y - y2) < 5) {
            _cursor = Cursor.S_RESIZE_CURSOR;
            cursor = Cursors._sCursor;
        }
        _presentor.setCursor(cursor);
    }

    /* ---------------------------------------------------------------------- */

    private MRectangleSelector() {
        _presentor = Presentor.Instance();
    }

    private static MRectangleSelector    _instance = null;

    private Presentor                   _presentor = null;
    private boolean                     _mouseDown = false;
    private int                         _cursor = Cursor.DEFAULT_CURSOR;
    private RectSelection               _selection = null;
}
